#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#===============================================================================
# Copyright 2011 zod.yslin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# 
# Author: zod.yslin
# Email: 
# File Name: list.py
# Description: 
#   Views And Iterators Instead Of Lists:
#       1.The dictionary methods keys(), values(), and items() are different in Python 3.x. 
#         They return an object called a view instead of a fully materialized list.
#       2.map() and filter() return iterators.
#       3.range() now behaves like xrange() used to behave, except it works with 
#         values of arbitrary size. The latter no longer exists.
#       4.zip() now returns an iterator.
# Edit History: 
#   2011-08-19    File created.
#===============================================================================
import pprint, sys
pp = pprint.PrettyPrinter(indent=2)

#===============================================================================
# 1.
#===============================================================================
d = dict((i*10, chr(65+i)) for i in range(4))
print(d)  # {0: 'A', 10: 'B', 20: 'C', 30: 'D'}
k = d.keys()     # return “views” instead of lists
i = d.items()    # return “views” instead of lists
v = d.values()   # return “views” instead of lists
pp.pprint(k)  # 2.7: [0, 10, 20, 30] , 3.0: dict_keys([0, 10, 20, 30])
pp.pprint(i)  # 2.7: [(0, 'A'), (10, 'B'), (20, 'C'), (30, 'D')], 3.0: dict_items([(0, 'A'), (10, 'B'), (20, 'C'), (30, 'D')])
pp.pprint(v)  # 2.7: ['A', 'B', 'C', 'D'] , 3.0: dict_values(['A', 'B', 'C', 'D'])
#pp.pprint(d.viewkeys())     # add only 2.7 to get its view, dict_keys([0, 10, 20, 30])
#pp.pprint(d.viewitems())    # add only 2.7 to get its view,
#pp.pprint(d.viewvalues())   # add only 2.7 to get its view,



print(k)  # 2.7: [0, 10, 20, 30], 3.0: dict_keys([0, 10, 20, 30])
d[260] = '&'
print(k)  # 2.7: [0, 10, 20, 30], 3.0: dict_keys([0, 260, 10, 20, 30])
print(d)  # {0: 'A', 260: '&', 10: 'B', 20: 'C', 30: 'D'}


# k.sort()  # It no longer works
key = sorted(d)  # this works in Python 2.5 too and is just as efficient
print(key)  # [0, 10, 20, 30, 260]
print(d)  # {0: 'A', 260: '&', 10: 'B', 20: 'C', 30: 'D'}


for kk in k:
    #d[kk*2] = kk  # RuntimeError: dictionary changed size during iteration
    print(kk)


#===============================================================================
# 2. map and filter
#===============================================================================
def test(x):
    return x > 10
 
a = [11, 2, 8, 22, 6, 4, 15]
for i in map(test, a):
    print(i)
print(map(test, a))  # 2.7: [True, False, False, True, False, False, True], 3.0: <map object at 0xb703e94c>

for i in filter(test, a):
    print(i)
print(filter(test, a))  # 2.7: [11, 22, 15], 3.0: <filter object at 0xb705898c>

#===============================================================================
# 3. range
#===============================================================================
a = range(10)  # The same as xrange(10) in 2.7
 
print("a: ", a)  # 2.7: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3.0: range(0, 10)
print("6 in a:", 6 in a)   # 2.7: True, 3.0: True
print("6 not in a:", 6 not in a)  # 2.7: False, 3.0: False
print("a[9]: ", a[9])  # 2.7: 9, 3.0: 9
print("len(a): ", len(a))  # 2.7: 10, 3.0: 10
print("max(a): ", max(a))  # 2.7: 9, 3.0: 9
print("min(a): ", min(a))  # 2.7: 0, 3.0: 0

#===============================================================================
# 4. zip
#===============================================================================
x = [1, 2, 3]
y = [4, 5, 6]
zipped = zip(x, y)
print(zipped)  # 2.7: [(1, 4), (2, 5), (3, 6)], 3.0: <zip object at 0xb70d09ac>
lz = list(zipped)
print(lz)  # [(1, 4), (2, 5), (3, 6)]
x2, y2 = zip(*zip(x, y))
print(x == x2, y == y2)  # False, False

